package com.card.game.room;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Random;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;

import com.card.common.CardContants;
import com.card.common.MessageComm;
import com.card.game.AqUtils;
import com.card.game.BasePlayer;
import com.card.game.Card;
import com.card.game.CardHeap;
import com.card.game.CardType;
import com.card.game.CardUtils;
import com.card.game.GameResult;
import com.card.game.Player;
import com.card.game.PlayerBei;
import com.card.game.PlayerEvent;
import com.card.game.BasePlayer.UserState;
import com.card.game.event.EventType;
import com.card.game.event.EventUtils;
import com.card.game.log.PlayerResult;
import com.card.game.log.ShLog;
import com.card.game.log.ShResults;
import com.card.game.playback.PlayBackManager;
import com.card.game.playback.Playback;
import com.card.game.utils.MjUtils;
import com.card.main.CardOnline;
import com.card.main.GameConfig;
import com.card.message.JsonMessageCenter;
import com.card.user.User;
import com.card.user.UserUtils;
import com.card.utils.Utils;
import com.google.common.collect.HashMultiset;
import com.google.common.collect.Lists;
import com.xiaoao.net.common.GameConstants;
import com.xiaoao.net.global.Global;
import com.xiaoao.net.json.message.JsonMessage;
import com.xiaoao.net.utils.StringUtil;

//水花
public class SHRoom extends AbstractRoom {
	public static final int Max_Num = 4;
	// 最大房间人数
	// gpgp新增参数
	public Card hunZi = new Card(0, 0);// 混子值

	//
	protected String zhuangId;// 庄家id
	private transient String preZhuangId;
	public int sieve = 2;
	protected int curwhosTurn = -1;
	private int faPaiIndex = 0;
	protected transient long curhowsTurnStartTime;
	protected Card lastOutCard;
	public String lastOutCardUser;
	protected transient List<PlayerEvent> events = Lists.newArrayList();

	protected transient ShResults shResults;
	protected transient GameResult gameResult;
	protected transient Playback playback;
	protected transient Card huCard;
	public PlayerEvent curEvent;
	private transient ReentrantLock roomLock;

	public SHRoom(String ownerId) {
		super(CardContants.GAMETYPE_SH, ownerId);
		this.roomLock = new ReentrantLock();
		this.zhuangId = ownerId;
		// this.preZhuangId = this.zhuangId;
		this.gameResult = new GameResult(this);
		this.shResults = new ShResults(this);
	}

	/**
	 * 麻将自动出牌
	 * 
	 */
	@Override
	public void doTimedTask() {
		if (state == RoomState.Ready) {
			long waitTime = System.currentTimeMillis() - this.stateChangeTime;
			if (waitTime > 2 * GameConstants.SECOND) {
				if (checkPlayerJiabei() || !roomSetting.isHasPao()) {
					randomSieve();
					// sendRoomInfo();
				}
			}
		} else if (state == RoomState.Running) {
			long waitTime = System.currentTimeMillis() - this.curhowsTurnStartTime;
			if (waitTime > 30 * GameConstants.SECOND) {
				autoOutCard();
			}
		} else if (state == RoomState.End && !isEndGame()) {
			long waitTime = System.currentTimeMillis() - this.stateChangeTime;
			if (waitTime > 2 * GameConstants.SECOND) {
				if (checkAllReady()) {
					if (roomSetting.isHasPao()) {
						broadPao();
					}
					System.out.println("ready");
					setState(RoomState.Ready);
				}
			}
		} else if (state == RoomState.HuState) {
			long waitTime = System.currentTimeMillis() - this.stateChangeTime;
			if (waitTime > 2 * GameConstants.SECOND) {
				setState(RoomState.Running);
				endGame();
				setState(RoomState.End);
			}
		}
	}

	public boolean checkAllReady() {
		boolean allReady = true;
		for (BasePlayer basePlayer : playerList) {
			if (basePlayer.getState() == UserState.None) {
				allReady = false;
			}
		}
		return allReady;
	}

	public boolean checkPlayerJiabei() {
		for (BasePlayer basePlayer : playerList) {
			Player player = getPlayerById(basePlayer.getUserId());
			if (player.isCanJiaBei) {
				return false;
			}
		}
		return true;
	}

	/**
	 * 麻将 自动出牌
	 * 
	 */
	public void autoOutCard() {
		if (this.curEvent != null) {
			if (this.curEvent.isZimo()) {
				doSkill(this.curEvent.getUserId(), EventType.ZiMo, 0);
			} else {
				JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_DoSkill);
				message.addProperty("type", EventType.Guo.toString());
				message.addProperty("userId", this.curEvent.getUserId());
				// message.addProperty("card", card);
				JsonMessageCenter.getInstance().sendMessage(message, this.curEvent.getUserId());
				doSkill(this.curEvent.getUserId(), EventType.Guo, 0);
			}
			return;
		}
		Player curPlayer = getPlayerByTableIndex(this.curwhosTurn);
		if (curPlayer != null) {
			// Global.logErrorMessage(curPlayer.getUserId()+"===========自动出牌===========");
			this.curhowsTurnStartTime = System.currentTimeMillis();
			handOut(curPlayer.getUserId(), curPlayer.getLastInCard(), false);
		}
	}

	@Override
	public void addPlayer(BasePlayer player) {
		synchronized (this.playerList) {
			player.addScore(getBaseScore());
			Player oldPlayer = getPlayerById(player.getUserId());
			if (oldPlayer != null) {
				return;
			}
			int tableIndex = randomTableIndex();
			player.setTableIndex(tableIndex);
			super.addPlayer(player);
			player.setState(UserState.Ready);
			// 通知所有人房间信息改变
			sendRoomInfo();
			if (this.playerList.size() == getMaxUserNum()) {
				if (roomSetting.isHasPao())
					broadPao();
				setState(RoomState.Ready);
			}
		}
		// 通知所有人房间信息改变
		// sendRoomInfo();
	}

	public void createTableCard() {
//		this.tableCards = CardUtils.createTestCards();
		 this.tableCards = CardUtils.createSHRoomCards(roomSetting.hasFeng());
	}

	// 生成混子
	public static Card createHunZi(boolean isHaveFeng) {
		// // 获取随机牌
		int r = new Random().nextInt(isHaveFeng ? 34 : 27);
		int type, index;
		if (r >= 27) {
			type = r % 9 + 4;
			index = 0;
		} else {
			type = r / 9 + 1;
			index = r % 9 + 1;
		}
		return new Card(type, index);
	}
	// 开始游戏
	@Override
	public void startGame() {
		// if(!isZhuang(preZhuangId)) {
		// }
		this.playNum++;
		super.startGame();
		Global.logErrorMessage("=================开始游戏==========");
		this.shResults.init();
		if (roomSetting.isHasHunzi()) {
			// 生成混子值--固定红中
			// hunZi = createHunZi(roomSetting.hasFeng());
			hunZi = new Card(CardType.ZHONG, 0);
			broadHunZi();
		}
		// System.out.println("混子值--------------:" + hunZi);
		// 生成牌
		createTableCard();
		System.out.println("生成牌");
		// Global.logErrorMessage("=================总牌数"+this.tableCards.size()+"==========");

		System.out.println("庄家ID:" + zhuangId);
		for (int i = 0; i < playerList.size(); i++) {
			Player player = (Player) playerList.get(i);
			int count = isZhuang(player.getUserId()) ? CardContants.CARD_INIT + 1 : CardContants.CARD_INIT;
			Vector<Card> outCard = CardUtils.faPaiToVector(this.tableCards, count);
			player.initCards(outCard);
		}
		// Global.logErrorMessage("=================总牌数"+this.tableCards.size()+"==========");

		this.playback = new Playback(this);
		playback.initRole(this);
		Player zhuang = getPlayerById(zhuangId);
		this.curwhosTurn = zhuang.getTableIndex();
		//
		broadFaPai();
		System.out.println("fapai===========");
		broadTableCard();
		System.out.println("显示桌面===========");
		for (int i = 0; i < playerList.size(); i++) {
			Player player = (Player) playerList.get(i);
			sendStarGameMessage(player);
		}
		this.curhowsTurnStartTime = System.currentTimeMillis();
		setState(RoomState.Running);
		System.out.println("开始打牌");
		Card lastCard = zhuang.getHand().cards.get(zhuang.getHand().cards.size() - 1);
		zhuang.setLastInCard(lastCard);
		zhuang.checkHandIn();
	}

	public boolean isZhuang(String userId) {
		return StringUtil.equals(userId, zhuangId);
	}

	public boolean isOwner(String userId) {
		return StringUtil.equals(userId, ownerId);
	}

	public String getZhuangId() {
		return zhuangId;
	}

	public int getCurwhosTurn() {
		return curwhosTurn;
	}

	public GameResult getGameResult() {
		return gameResult;
	}

	public boolean isFull() {
		synchronized (playerList) {
			return this.playerList.size() == getMaxUserNum();
		}
	}

	public void sendStarGameMessage(Player player) {
		JsonMessage message = new JsonMessage(MessageComm.S2C_StartGame);
		message.addProperty("hand", player.getHand().cards);
		message.addProperty("curwhosTurn", curwhosTurn);
		message.addProperty("tableSize", this.tableCards.size());
		if (GameConfig.ShowTing && player.getHand().cards.size() == CardContants.CARD_INIT) {
			List<Card> tingCards = getShowTingCards(player);
			player.setShowTingCards(tingCards);
			message.addProperty("tingCards", tingCards);
		}
		JsonMessageCenter.getInstance().sendMessage(message, player);
	}

	public void sendUpdateCards(Player player, Card lastCard) {
		JsonMessage message = new JsonMessage(MessageComm.S2C_HandUpdate);
		message.addProperty("hand", player.getHand().cards);
		message.addProperty("lastInCard", lastCard);
		message.addProperty("curwhosTurn", curwhosTurn);
		JsonMessageCenter.getInstance().sendMessage(message, player);
	}

	public void sendUpdateCards(Player player, boolean showTing) {
		JsonMessage message = new JsonMessage(MessageComm.S2C_HandUpdate2Out);
		message.addProperty("hand", player.getHand().cards);
		if (GameConfig.ShowTing && showTing) {
			List<Card> tingCards = getShowTingCards(player);
			player.setShowTingCards(tingCards);
			message.addProperty("tingCards", tingCards);
		}
		JsonMessageCenter.getInstance().sendMessage(message, player);
	}

	public void sendBreakCards(Player player, Card lastCard) {
		JsonMessage message = new JsonMessage(MessageComm.S2C_HandUpdate);
		Vector<Card> handCards = (Vector<Card>) player.getHand().cards.clone();
		handCards.remove(lastCard);
		message.addProperty("hand", handCards);
		message.addProperty("lastInCard", lastCard);
		message.addProperty("curwhosTurn", curwhosTurn);
		JsonMessageCenter.getInstance().sendMessage(message, player);
	}

	public void randomSieve() {
		setState(RoomState.Sieve);
		int seed1 = Utils.randomSieve();
		int seed2 = Utils.randomSieve();
		this.sieve = seed1 + seed2;
		this.faPaiIndex = Utils.getFirstIndex(this.sieve);
		JsonMessage message = new JsonMessage(MessageComm.S2C_RandomSieve);
		message.addProperty("seed1", seed1);
		message.addProperty("seed2", seed2);
		message.addProperty("faPaiIndex", faPaiIndex);
		broadcast(message);
		System.out.println("faPaiIndex");

		startGame();
	}

	@Override
	public void handOut(String userId, Card outCard, boolean isTing) {
		roomLock.lock();
		try {
			handOutNoLock(userId, outCard, isTing);
		} finally {
			roomLock.unlock();
		}
	}

	public void handOutNoLock(String userId, Card outCard, boolean isTing) {
		Player player = getPlayerById(userId);
		if (player.getTableIndex() != curwhosTurn || player.getHandSize() % 3 != 2) {
			Global.logErrorMessage(player.getUserId() + "/" + player.getTableIndex() + "========不该你出牌！！！！"
					+ (player.getHandSize() % 3 != 2));
			return;
		}
		if (player.ting) {
			isTing = false;
		}
		isTing = GameConfig.isTing && isTing;
		outCard = player.handOut(outCard, isTing);
		if (outCard.isHuaCard()) {
			buHuaPai(player, outCard);
			return;
		}
		player.isTianHu = false;
		player.getPlayerInfo().setWaitType(null);

		if (isTing && player.tingCard()) {
			player.getOutCards().remove(player.getOutCards().size() - 1);
			outCard = Card.getTingCard();
			player.getOutCards().add(outCard);
			gameResult.addTingCard(userId);
			broadSkill(EventType.Ting, player, outCard);
			isTing = true;
		}

		this.lastOutCard = outCard;
		this.lastOutCardUser = userId;
		JsonMessage message = new JsonMessage(MessageComm.S2C_HandOut);
		message.addProperty("userId", userId);
		message.addProperty("outCard", outCard);
		message.addProperty("ting", isTing);
		broadcast(message);// 广播出牌
		broadTableCard();
		sendUpdateCards(player, true);
		playback.addBackEvent(EventType.Chupai, player, outCard);
		// 判断跟庄
		if (GameConfig.isGenZhuang)
			EventUtils.checkGenZhuang(this, player);
		// 检查出牌
		checkHandOut(player);
	}

	private boolean buHuaPai(Player player, Card card) {
		player.addHuaPai(card);
		// change
		JsonMessage m4 = new JsonMessage(MessageComm.S2C_FindHuaPai);
		m4.addProperty("userId", player.getUserId());
		broadcast(m4);
		playback.addBackEvent(EventType.BuHua, player, null);
		sendUpdateCards(player, true);
		player.getPlayerInfo().setWaitType(EventType.GangTouKaiHua);

		nextDoPlayer(player.getTableIndex());
		return false;
	}

	public Player getPlayerById(String userId) {
		return (Player) super.getPlayerById(userId);
	}

	public Player getPlayerByTableIndex(int index) {
		return (Player) super.getPlayerByTableIndex(index);
	}

	// 下一家出牌处理
	public void nextDoPlayer() {
		// 通知其他人发牌
		int nextTurn = getNextPlayer();
		nextDoPlayer(nextTurn);
	}

	public void nextDoPlayer(int nextTurn) {
		// 广播发牌
		// broadLastHandOut();
		// 通知其他人发牌
		changeWhoTurn(nextTurn);
		// 广播当前桌的情况
		broadTableCard();

		if (this.tableCards.isEmpty()) {
			doLiuju();
			return;
		}
		Card oneCard = CardUtils.faPaiOne(this.tableCards);
		Player curPlayer = getPlayerByTableIndex(this.curwhosTurn);
		sendUpdateCards(curPlayer, oneCard);
		playback.addBackEvent(EventType.Qipai, curPlayer, oneCard);

		curPlayer.clearNoHuCard();

		curPlayer.addCard(oneCard);
		broadFaPai();
		// 检查自己的牌
		curPlayer.checkHandIn();
	}

	public void changeWhoTurn(int nextTurn) {
		clearHandEvent();
		this.curwhosTurn = nextTurn;
		this.curhowsTurnStartTime = System.currentTimeMillis();
	}

	public void broadFaPai() {
		broadChuPai();
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_FaPai);
		message.addProperty("curwhosTurn", curwhosTurn);
		int cardSize = this.tableCards.size();
		message.addProperty("tableSize", cardSize);
		// message.addProperty("cardWall",
		// CardWallUtils.calCardWall(roomSetting.isNoFeng(), cardSize, sieve,
		// getGangSize()));
		broadcast(message);
		// broadChuPai();
	}

	public void broadHunZi() {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_HunZi);
		message.addProperty("hunzitype", hunZi.getType());
		message.addProperty("hunziindex", hunZi.getIndex());
		broadcast(message);
	}

	public void broadPao() {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_ShowJiaBei);
		broadcast(message);
	}

	public void broadChuPai() {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_ChuPai);
		message.addProperty("curwhosTurn", curwhosTurn);
		broadcast(message);

		Player player = getPlayerByTableIndex(curwhosTurn);
		if (player != null) {
			if (player.getHand().cards.size() == 13) {
				Global.logErrorMessage("出牌者:13牌");
				try {
					System.err.println(1 / 0);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
	}

	public int getNextPlayer() {
		return curwhosTurn == getMaxUserNum() - 1 ? 0 : curwhosTurn + 1;
	}

	public int getNextPlayerByIndex(int tableIndex) {
		return tableIndex == getMaxUserNum() - 1 ? 0 : tableIndex + 1;
	}

	public int getPrePlayerByIndex(int tableIndex) {
		return tableIndex == 0 ? getMaxUserNum() - 1 : tableIndex - 1;
	}

	public Card getLastOutCard() {
		return lastOutCard;
	}

	// public int getGangSize() {
	// int gangSize = 0;
	// for (int i = playerList.size()-1; i >= 0; i--) {
	// gangSize +=
	// playerList.get(i).getGangCardsList().size()+playerList.get(i).getAnGangList().size();
	// }
	// return gangSize;
	// }

	// 提醒解散
	public void remindDisband() {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_RoomRemindDisband);
		message.addProperty("info", "房间再一分钟后解散");
		broadcast(message);
		this.isRemindDisband = true;
	}

	@Override
	public void disbandRoom() {
		// 弹出结算
		if (isStartGame) {
			shResults.saveScore();
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_SH_ALL_GAME_OVER);
			message.addProperty("results", shResults.getResultList());
			message.addProperty("isDisband", 1);
			broadcast(message);
		} else {
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_RoomDisband);
			message.addProperty("firstId", this.firstDisandRequestId != null ? this.firstDisandRequestId : "-1");
			broadcast(message);
		}
		super.clearRoom();
	}

	@Override
	public void disbandAgencyRoom() {
		// 弹出结算
		if (isStartGame) {
			shResults.saveScore();
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_SH_ALL_GAME_OVER);
			message.addProperty("results", shResults.getResultList());
			message.addProperty("isDisband", 1);
			broadcast(message);
		} else {
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_DisbandAgencyCreateRoom);
			message.addProperty("firstId", this.firstDisandRequestId != null ? this.firstDisandRequestId : "-1");
			broadcast(message);
		}
		super.clearRoom();
	}

	private boolean isRemindDisband = false;
	// @Override
	// public void doTimedTask() {
	// super.doTimedTask();
	// if(!isStartGame && state == RoomState.Wait) {
	// long waitTime = System.currentTimeMillis() - this.stateChangeTime;
	// if(waitTime > GameConstants.HOURR && this.playerList.size() == 1) {
	// disbandRoom();
	// }
	// }else if(!isStartGame && state == RoomState.Ready) {
	// long waitTime = System.currentTimeMillis() - this.stateChangeTime;
	// if(waitTime > 2*GameConstants.SECOND) {
	// doJiabeiAction();
	// }
	// }else if(state == RoomState.Running) {
	//// long waitTime = System.currentTimeMillis() - this.curhowsTurnStartTime;
	//// if(!isRemindDisband && waitTime >
	// GameSetting.HandOutTimeOutDisbandSecond*GameConstants.SECOND) {
	//// //提醒房间里的人将要解散
	//// remindDisband();
	//// }else if(waitTime > GameSetting.HandOutTimeOutSecond*GameConstants.SECOND)
	// {
	//// disbandRoom();
	//// }else {
	//// }
	// }else if(state == RoomState.HuState) {
	// long waitTime = System.currentTimeMillis() - this.stateChangeTime;
	// if(waitTime > GameConstants.SECOND) {
	// setState(RoomState.Running);
	// endGame();
	// }
	// }
	// }

	// 随机座位
	public int randomTableIndex() {
		if (this.playerList.isEmpty()) {
			return 1;
		}
		List<Integer> allIndex = Lists.newArrayList();
		for (int i = 0; i < getMaxUserNum(); i++) {
			allIndex.add(i);
		}
		// List<Integer> allIndex = Lists.newArrayList(0,1,2,3);
		Iterator<BasePlayer> it = this.playerList.iterator();
		while (it.hasNext()) {
			BasePlayer temp = it.next();
			allIndex.remove(Integer.valueOf(temp.getTableIndex()));
		}
		return allIndex.get(new Random().nextInt(allIndex.size()));
	}

	@Override
	public void doSkill(String userId, EventType type, int cardIndex) {
		Player player = getPlayerById(userId);
		// System.err.println("====tablesize:"+this.tableCards.size());
		if (curEvent == null || !StringUtil.equals(userId, curEvent.getUserId())) {
			Global.logErrorMessage(player.getTableIndex() + "=====不该出发技能！！！" + (curEvent == null));
			return;
		}
		if (this.curEvent.isCanQiangGang()) {
			if (type == EventType.Hu) {
				type = EventType.QiangGang;
			} else if (type == EventType.Guo) {
				type = EventType.BuQiang;
			}
		}
		boolean isCanHu = this.curEvent.isCanHu();
		boolean isZimo = this.curEvent.isZimo();
		// List<Card> chiCards = this.curEvent.getChiCards(cardIndex);
		List<Card> gangList = this.curEvent.getGangList();
		Card gangCard = null;
		if (!gangList.isEmpty() && type == EventType.AnGang) {
			if (player.getTableIndex() != curwhosTurn) {
				type = EventType.FangGang;
			}
			gangCard = gangList.get(cardIndex);
			if (player.getDuiCards().containsKey(gangCard)) {
				type = EventType.GuoLuGang;
			}
		}
		PlayerEvent tempEvent = this.curEvent;
		this.curEvent = null;
		if (type == EventType.Guo) {
			if (!gameResult.getHuList().isEmpty()) {
				if (roomSetting.getMaima() > 0) {

				} else {
					setState(RoomState.HuState);
				}
				return;
			} else {
				if (isCanHu && lastOutCard != null) {
					player.addNoHuCard(lastOutCard);
				} else if (isZimo) {
					// 是自摸过的,让玩家出牌
					player.addNoHuCard(player.getLastInCard());
					if (GameConfig.isTing) {
						handOut(userId, player.getLastInCard(), false);
					} else {
						broadFaPai();// 通知出牌
					}
					return;
				} else if (!gangList.isEmpty() && player.getTableIndex() == curwhosTurn) {
					if (player.ting) {
						handOut(userId, player.getLastInCard(), false);
					} else {
						broadChuPai();
						return;
					}

				} else if (player.ting && player.getTableIndex() == this.curwhosTurn) {
					handOut(userId, player.getLastInCard(), false);
					return;
				}
				doEvents();
			}
			return;
		}
		Player curPlayer = getPlayerByTableIndex(this.curwhosTurn);
		if (type == EventType.Peng) {
			if (EventUtils.doPeng(player.getHand().cards, lastOutCard)) {
				// 广播发牌
				// broadLastHandOut();
				changeWhoTurn(player.getTableIndex());
				player.setLastInCard(null);
				player.clearNoHuCard();
				// curPlayer.removeOutCard(lastOutCard);
				curPlayer.removeLastOutCard(lastOutCard);
				player.pengCard(lastOutCard, curPlayer.getUserId());
				broadSkill(EventType.Peng, player, lastOutCard);
				// 广播当前桌的情况
				broadTableCard();
				sendUpdateCards(player, false);
				broadFaPai();
				player.checkHandIn(false);
				return;
			}
		} else if (type == EventType.Chi) {
			if (false) {
				// if (!chiCards.isEmpty() && chiCards.contains(lastOutCard)) {
				changeWhoTurn(player.getTableIndex());
				player.setLastInCard(null);
				curPlayer.removeOutCard(lastOutCard);
				// player.chiCard(lastOutCard, chiCards, this.lastOutCardUser);
				broadSkill(EventType.Chi, player, lastOutCard);
				broadTableCard();
				sendUpdateCards(player, false);
				broadFaPai();
				return;
			}
		} else if (type == EventType.AnGang) {
			System.out.println("-----anGang");
			Card anGang = gangCard;
			if (anGang != null) {
				if (checkQiangGang(userId, anGang, EventType.AnGang)) {
					this.lastOutCard = gangCard;
					return;
				}
				player.anGangCard(anGang);
				broadSkill(type, player, anGang);
				gameResult.calAnGangScore(userId, 1);
				player.getPlayerInfo().setWaitType(EventType.GangTouKaiHua);
				firstToEnd();
				nextDoPlayer(player.getTableIndex());
				return;
			}
		} else if (type == EventType.GuoLuGang) {
			System.out.println("-----guoGang");
			Card lastInCard = gangCard;
			if (lastInCard != null) {
				if (checkQiangGang(userId, lastInCard, EventType.GuoLuGang)) {
					this.lastOutCard = lastInCard;
					return;
				}
				String gangUserId = player.removeDuiCard(lastInCard);
				player.mingGangCard(lastInCard, gangUserId);
				gameResult.calAnGangScore(userId, 1);
				player.getPlayerInfo().setWaitType(EventType.GangTouKaiHua);
				broadSkill(type, player, lastInCard);
				firstToEnd();
				nextDoPlayer(player.getTableIndex());
				return;
			}
		} else if (type == EventType.FangGang) {
			if (player.getHand().isCanMingGang(this.lastOutCard)) {
				if (checkQiangGang(player.getUserId(), this.lastOutCard, EventType.FangGang)) {
					this.curwhosTurn = player.getTableIndex();
					return;
				}
				System.out.println("-----FangGang");
				player.mingGangCard(lastOutCard, curPlayer.getUserId());
				// player.addBaoPai(userId);
				broadSkill(type, player, lastOutCard);
				curPlayer.removeOutCard(lastOutCard);
				player.getPlayerInfo().setWaitType(EventType.GangTouKaiHua);
				System.out.println(player.getUserId() + "_:_" + curPlayer.getUserId());
				gameResult.calFangGangScore(player, curPlayer.getUserId(), this.lastOutCard.getScore());
				firstToEnd();
				nextDoPlayer(player.getTableIndex());
				return;
			}
		} else if (type == EventType.BuQiang) {
			player = curPlayer;// 不抢之后,玩家出杠
			if (tempEvent.getGangType() == EventType.FangGang) {
				System.out.println("fangGang-----");
				curPlayer = getPlayerById(this.lastOutCardUser);
				if (player.getHand().isCanMingGang(this.lastOutCard)) {
					player.mingGangCard(lastOutCard, curPlayer.getUserId());
					player.addBaoPai(userId);
					broadSkill(type, player, lastOutCard);
					curPlayer.removeOutCard(lastOutCard);
					gameResult.calFangGangScore(player, curPlayer.getUserId(), this.lastOutCard.getScore());
					nextDoPlayer(player.getTableIndex());
					return;
				}
			} else if (tempEvent.getGangType() == EventType.GuoLuGang) {
				System.out.println("GuoLuGang-----");
				Card lastInCard = player.getLastInCard();
				if (lastInCard != null && player.getDuiCards().containsKey(lastInCard)) {
					String gangUserId = player.removeDuiCard(lastInCard);
					player.mingGangCard(lastInCard, gangUserId);
					broadSkill(type, player, lastInCard);
					nextDoPlayer(player.getTableIndex());
					return;
				}
			} else if (tempEvent.getGangType() == EventType.AnGang) {
				System.out.println("angang-----");
				Card anGang = this.lastOutCard;
				if (anGang != null) {
					player.anGangCard(anGang);

					broadSkill(type, player, anGang);
					gameResult.calAnGangScore(userId, anGang.getScore());
					nextDoPlayer(player.getTableIndex());
				}
			}

		} else if (type == EventType.Hu || type == EventType.QiangGang) {
			// 收到胡牌消息??
			// if(player.isCanHu(this.lastOutCard)) {
			//
			// }
			if (type == EventType.QiangGang) {
				if (tempEvent.getGangType() != EventType.FangGang) {
					curPlayer.removeCard(lastOutCard);
				}
			}
			broadSkill(type, player, this.lastOutCard);
			gameResult.calHuScore(userId, curPlayer.getUserId(), this.lastOutCard, type);
			if (!isHZRoom() && !this.events.isEmpty()) {
				// PlayerEvent event = this.events.get(0);
				for (PlayerEvent event : this.events) {
					if (event.isCanHu()) {
						// doEvents();
						// return;
						Player huPlayer = getPlayerById(event.getUserId());
						broadSkill(type, huPlayer, this.lastOutCard);
						gameResult.calHuScore(event.getUserId(), curPlayer.getUserId(), this.lastOutCard, type);
					}
				}
			}
			setState(RoomState.HuState);
			return;
		} else if (type == EventType.ZiMo) {
			if (player.isZimo()) {
				EventType eventType = type;
				if (GameConfig.isCanGangKaiHua) {
					eventType = player.getPlayerInfo().getWaitType() != null ? player.getPlayerInfo().getWaitType()
							: type;
				}

				broadSkill(eventType, curPlayer, player.getLastInCard());
				gameResult.calZiMoScore(userId, eventType);
				setState(RoomState.HuState);
				return;
			}
		}
		Global.logErrorMessage(player.getTableIndex() + "=====无效技能！！！" + type.toString());

	}

	public void broadSkill(EventType type, Player player, Card card) {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_DoSkill);
		message.addProperty("type", type.toString());
		message.addProperty("userId", player.getUserId());
		message.addProperty("card", card);
		// 发送抓马,
		if ((type == EventType.ZiMo || type == EventType.Hu) && roomSetting.getMaima() > 0) {
			for (int i = 0; i < roomSetting.getMaima(); i++) {
				Card rc = CardUtils.faPaiOne(this.tableCards);
				if (rc.getType() <= CardType.BING) {
					if (rc.getIndex() == 1 || rc.getIndex() == 5 || rc.getIndex() == 9) {
						maList.add(rc);
						maString += rc.getType() + "," + rc.getIndex() + ";";
					}
				} else {
					if (rc.getType() == 4 || rc.getType() == 8) {
						maList.add(rc);
						maString += rc.getType() + "," + rc.getIndex() + ";";
					}
				}
			}
			message.addProperty("ma", maList);
			message.addProperty("maString", maString);
//			System.out.println("maList" + maList);
			System.out.println("maString" + maString);
		}
		broadcast(message);
		playback.addBackEvent(type, player, card);
	}

	public List<Card> maList = new ArrayList<>();
	public String maString = "";

	public void broadSkill(EventType type) {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_DoSkill);
		message.addProperty("type", type);
		broadcast(message);
		playback.addBackEvent(type, null, null);
	}

	// private void broadLastHandOut() {
	// JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_LastHandOut);
	// Player player = getPlayerByTableIndex(this.curwhosTurn);
	// message.addProperty("userId", player.getUserId());
	// message.addProperty("outcard", this.lastOutCard);
	// broadcast(message);
	// //判断跟庄
	// EventUtils.checkGenZhuang(this,player);
	// }

	// 广播当前桌子上的情况
	public void broadTableCard() {
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_TableHands);
		message.addProperty("playerList", this.playerList);
		broadcast(message);
	}

	public void clearHandEvent() {
		this.events.clear();
		this.curEvent = null;
	}

	@Override
	public void setEvent(PlayerEvent event) {
		this.curEvent = event;
	}

	public void checkHandOut(Player player) {
		clearHandEvent();
		if (this.lastOutCard.getType() >= 0) {
			Iterator<BasePlayer> it = this.playerList.iterator();
			while (it.hasNext()) {
				// 判断是否有人胡、杠，对
				Player temp = (Player) it.next();
				if (!StringUtil.equals(player.getUserId(), temp.getUserId())) {
					PlayerEvent event = temp.getHandOutEvent(this, this.lastOutCard, this.curwhosTurn, player);
					if (event != null)
						this.events.add(event);
				}
			}
			// if(!this.events.isEmpty()) {
			// Collections.sort(this.events);
			// }
		}
		sortEvents();
		doEvents();
	}

	private void sortEvents() {
		if (this.events.isEmpty()) {
			return;
		}
		if (GameConfig.FenHu) {
			List<PlayerEvent> huEvent = Lists.newArrayList();
			for (PlayerEvent playerEvent : this.events) {
				if (playerEvent.isCanHu())
					huEvent.add(playerEvent);
			}
			for (PlayerEvent event : huEvent) {
				PlayerEvent otherEvent = event.getOtherEvent();
				if (otherEvent != null) {
					this.events.add(otherEvent);
				}
			}
		}
		if (!this.events.isEmpty()) {
			Collections.sort(this.events);
		}
	}

	public void doEvents() {
		if (this.events.isEmpty()) {
			nextDoPlayer();
			return;
		}
		PlayerEvent event = this.events.remove(0);
		this.curEvent = event;
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_PlayerEvent);
		message.addProperty("event", event);
		JsonMessageCenter.getInstance().sendMessage(message, event.getUserId());
	}

	public void doLiuju() {
		gameResult.setLiuJu(true);
		broadSkill(EventType.LiuJu);
		setState(RoomState.HuState);
	}

	@Override
	public void endGame() {
		gameResult.calResult();
		shResults.calResult();
		this.preZhuangId = this.zhuangId;
		this.zhuangId = gameResult.getNextZhuangId();
		sendEnd2Player();

		super.endGame();
		// gpgp
		for (int i = playerList.size() - 1; i >= 0; i--) {
			BasePlayer basePlayer = playerList.get(i);
			Player player = getPlayerById(basePlayer.getUserId());
			player.jiaBei = 0;
			player.isCanJiaBei = true;
		}
		//
		this.lastOutCard = null;
		this.huCard = null;
		this.gameResult.endGame();
		clearHandEvent();
		syncMatchScore();
		if (isEndGame()) {
			// 全局结束
			calAllGame();
		}
	}

	public void syncMatchScore() {
	}

	public void calAllGame() {
		shResults.saveScore();
		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_SH_ALL_GAME_OVER);
		message.addProperty("results", shResults.getResultList());
		message.addProperty("roomLogs", shResults.getRoomLogs());
		broadcast(message);
		clearRoom();
	}

	public boolean isEndGame() {
		if (this.playNum >= roomSetting.getMaxPlayNum()
		// && !isZhuang(preZhuangId)
		) {
			return true;
		}
		return false;
	}

	@Override
	public void clearRoom() {
		super.clearRoom();
		this.shResults.clear();
	}

	public void sendEnd2Player() {
		ShLog shLog = new ShLog(getId());
		List<PlayerResult> resultList = Lists.newArrayList();
		for (int i = this.playerList.size() - 1; i >= 0; i--) {
			Player temp = (Player) playerList.get(i);
			int gangScore = gameResult.getGangScore(temp.getUserId());
			int fanScore = gameResult.getFanScore(temp.getUserId());
			int otherScore = gameResult.getOtherScore(temp.getUserId());
			int sumScore = gangScore + fanScore + otherScore;
			temp.addScore(sumScore);

			Global.logErrorMessage(temp.getUserId() + ":" + temp.nickName + "=   gangScore:" + gangScore
					+ "   fanScore:" + fanScore + "   sumScore:" + sumScore);
			// System.out.println(temp.getUserId() + ":" + temp.nickName + "= gangScore:" +
			// gangScore + " fanScore:"
			// + fanScore + " sumScore:" + sumScore);
			String showInfo = gameResult.getShowInfo(temp.getUserId());
			Global.logErrorMessage(temp.getUserId() + ":" + showInfo);

			PlayerResult result = new PlayerResult(temp.getUserId(), temp.getHand().cards, temp.getAllGangList(),
					temp.getHuaPaiList(), temp.getDuiCardsList(), temp.getChiList(),
					gameResult.getEventType(temp.getUserId()), gangScore, fanScore, sumScore, 0, showInfo);
			result.calHuCard(temp.getLastInCard(), lastOutCard,
					StringUtil.equals(temp.getUserId(), getGameResult().getZimoId()),
					getGameResult().isHu(temp.getUserId()));
			if (gameResult.isWinUser(temp.getUserId())) {
				resultList.add(0, result);
			} else {
				resultList.add(result);
			}
			shLog.addLog(temp.getUserId(), temp.nickName, sumScore);
		}
		if (!isMatchRoom()) {
			// 保存录像
			playback.setResultList(resultList);
			String id = PlayBackManager.getInstance().savePlayback(shResults, playback, ownerId, shLog);
		}
		shResults.addRoomLog(shLog);

		JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_SH_GAME_END);
		message.addProperty("results", resultList);
		message.addProperty("playNum", playNum);
		message.addProperty("playBackId", 1);
		message.addProperty("zhuangId", this.zhuangId);
		int[] playerScores = getPlayerScore();
		Global.logErrorMessage("playerScores" + Arrays.toString(playerScores));
		message.addProperty("playerScores", playerScores);
		if (isHZRoom()) {
			message.addProperty("luckCards", getLuckCard());
		}
		// gameResult.fillMsg(message);
		broadcast(message);
	}

	@Override
	public void checkSameIp(BasePlayer player) {
		String ip = player.getIp();
		List<String> sameIps = getPlayerNameByIp(ip);
		if (sameIps.size() > 1) {
			StringBuilder sb = new StringBuilder();
			for (int i = 0; i < sameIps.size(); i++) {
				sb.append(sameIps.get(i));
				if (i != sameIps.size() - 1)
					sb.append("、");
			}
			JsonMessage message = new JsonMessage(MessageComm.S2C_ErrorMsg);
			message.addProperty("msg", "玩家" + sb.toString() + "的IP相同，请保持警惕！");
			broadcast(message);
		}
		sameIps.clear();
	}
	
	
	//检查gps
	@Override
	public void checkSameGPS(BasePlayer player) {
		User user = player.getUser();
		double gps = player.getGps();
		double gps2 = player.getGps2();
		System.out.println(gps+"========================="+gps2);
		JsonMessage message = new JsonMessage(MessageComm.S2C_GPS);
		for (int i=0;i<this.playerList.size();i++) {
			BasePlayer basePlayer = playerList.get(i);
			System.out.println(basePlayer.getUser().getPrimaryKey());
			System.out.println(player.getUser().getPrimaryKey());
			if (!player.getUser().getPrimaryKey().equals(basePlayer.getUser().getPrimaryKey())) {
				
				String playername = player.getUser().getUserExtra().getNickName();
				String basePlayername = basePlayer.getUser().getUserExtra().getNickName();
				double distance = MjUtils.getDistance(gps, gps2, basePlayer.getGps(), basePlayer.getGps2());
				System.out.println("------"+playername+"------"+basePlayername+"-----"+distance);
				message.addProperty("gpsInfo"+i,"#"+playername+"-"+basePlayername+"-"+distance+"#");
			}
		}
		JsonMessageCenter.getInstance().sendMessage(message, user);
		
		/*while (it.hasNext()) {
			BasePlayer player1 = it.next();
			double distance = MjUtils.getDistance(gps, gps2, player1.getGps(), player1.getGps2());
			names.add("#"+player.nickName+"-"+player1.nickName+"-"+distance+"#");
		}
		
		List<String> sameGpss = getPlayerNameByGPS(player);
		if(sameGpss.size()>1) {
				StringBuilder sb = new StringBuilder();
				for (int i = 0; i < sameGpss.size(); i++) {
					sb.append(sameGpss.get(i));
					if (i != sameGpss.size() - 1)
						sb.append("、");
				}
				JsonMessage message = new JsonMessage(MessageComm.S2C_GPS);
				message.addProperty("gpsmsg", sb.toString());			
				broadcast(message);
		}
		sameGpss.clear();*/
	}
	
	

	@Override
	public void breakConnect(BasePlayer temp) {
		Global.logCommMessage("=============Sh断线重连=====================");
		JsonMessage message1 = new JsonMessage(MessageComm.C2S_BreakConnect);
		message1.addProperty("room", this);
		JsonMessageCenter.getInstance().sendMessage(message1, temp);

		Player player = (Player) temp;
		if (isStartGame) {
			// 游戏已经开始了
			if (curwhosTurn == player.getTableIndex() && player.getHandSize() % 3 == 2) {
				sendBreakCards(player, player.getLastInCard());
			} else {
				sendUpdateCards(player, true);
			}
			JsonMessage m2 = JsonMessage.createMessage(MessageComm.S2C_FaPai);
			m2.addProperty("curwhosTurn", curwhosTurn);
			int cardSize = this.tableCards.size();
			m2.addProperty("tableSize", cardSize);
			// m2.addProperty("cardWall", CardWallUtils.calCardWall(roomSetting.isNoFeng(),
			// cardSize, sieve, getGangSize()));
			JsonMessageCenter.getInstance().sendMessage(m2, player);

			if (this.curEvent != null && StringUtil.equals(this.curEvent.getUserId(), player.getUserId())) {
				// if(curEvent.isCanTing()) {
				// Thread.sleep(100);
				// }
				JsonMessage m3 = JsonMessage.createMessage(MessageComm.S2C_PlayerEvent);
				m3.addProperty("event", curEvent);
				JsonMessageCenter.getInstance().sendMessage(m3, curEvent.getUserId());
			}
			if (this.state == RoomState.DisbandRequest) {
				sendDisandRoomRequest();
			}
		}
		player.changeOnline(true);
		if (GameConfig.HaveJiaBei) {
			canShowJiabei(player);
		}
	}

	public List<CardHeap> getCanChiList(Player player) {
		if (isCanChi() && getPrePlayerByIndex(player.getTableIndex()) == curwhosTurn && this.lastOutCard != null) {
			return player.getHand().getCanChiList(this.lastOutCard);
		}
		return null;
	}

	public boolean isCanChi() {
		return false;
	}

	public int getBaseScore() {
		return 0;
	}

	public ShResults getShResults() {
		return shResults;
	}

	public boolean checkQiangGang(String userId, Card lastInCard, EventType gangType) {

		if (GameConfig.isOnlyZimo || gangType == EventType.AnGang && !roomSetting.isCanQiangAnGang()
				|| gangType == EventType.FangGang && !GameConfig.qiangMingGang
				|| gangType == EventType.GuoLuGang && !GameConfig.qiangGuoluGang || lastInCard == null) {
			return false;
		}
		Player player = getPlayerById(userId);
		Iterator<BasePlayer> it = this.playerList.iterator();
		while (it.hasNext()) {
			Player temp = (Player) it.next();
			if (!StringUtil.equals(userId, temp.getUserId()) && temp.checkQiangGang(this, lastInCard, player)) {
				this.curEvent.setGangType(gangType);
				return true;
			}
		}
		return false;
	}

	public Card getJinPai() {
		return null;
	}

	public void firstToEnd() {
		// if(this.tableCards.size() > 0) {
		// Card first = this.tableCards.remove(0);
		// if(first.isLiujuCard() && this.tableCards.size() > 0) {
		// first.setLiujuCard(false);
		// }
		// this.tableCards.add(first);
		// }
	}

	public void sendRoomBei() {
		List<PlayerBei> pbs = Lists.newArrayList();
		Iterator<BasePlayer> it = playerList.iterator();
		while (it.hasNext()) {
			Player p = (Player) it.next();
			if (!p.isCanJiaBei) {
				pbs.add(new PlayerBei(p));
			}
		}
		JsonMessage message = new JsonMessage(MessageComm.S2C_JiaBei);
		message.addProperty("data", pbs);
		broadcast(message);
	}

	public boolean checkCanSieve() {
		for (int i = playerList.size() - 1; i >= 0; i--) {
			Player temp = (Player) playerList.get(i);
			if (temp.isCanJiaBei) {
				return false;
			}
		}
		return this.state == RoomState.JiaBei;
	}

	public void doJiabeiAction() {
		if (roomSetting.isHasPao()) {
			setState(RoomState.JiaBei);
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_ShowJiaBei);
			message.addProperty("second", CardOnline.ShowBeiSecond);
			broadcast(message);
			setState(RoomState.Ready);
		} else {
			randomSieve();
		}
	}

	public void canShowJiabei(Player player) {
		if (RoomState.JiaBei == this.state) {
			if (player.isCanJiaBei) {
			}
			JsonMessage message = JsonMessage.createMessage(MessageComm.S2C_ShowJiaBei);
			message.addProperty("second", CardOnline.ShowBeiSecond);
			JsonMessageCenter.getInstance().sendMessage(message, player);
		}
		sendRoomBei();
	}

	@Override
	public int getMaxUserNum() {
		// return Max_Num;
		return roomSetting.getUserNum();
	}

	public List<Card> getShowTingCards(Player player) {
		// gpgp
		// System.out.println("getShowTingCards------获取");
		// List<Card> tingCard = AqUtils.getTingCards(player.getHand().cards);
		List<Card> tingCard = AqUtils.getTingCards(player.getHand().cards, roomSetting.hasFeng(), hunZi);
		// calLastCard(tingCard, player.getUserId());
		return tingCard;
	}

	private void calLastCard(List<Card> tingCard, String userId) {
		HashMultiset<Card> counMap = getLastNum(userId);
		for (Card card : tingCard) {
			card.setLastNum(String.valueOf(counMap.count(card)));
		}
		counMap.clear();
	}

	private HashMultiset<Card> getLastNum(String userId) {
		HashMultiset<Card> countMap = HashMultiset.create();
		List<Card> allCards = Lists.newArrayList();
		allCards.addAll(this.tableCards);
		for (BasePlayer p : this.playerList) {
			Player sp = (Player) p;
			if (!StringUtil.equals(userId, sp.getUserId())) {
				allCards.addAll(sp.getHand().cards);
			}
		}
		for (Card card : allCards) {
			countMap.add(card);
		}
		return countMap;
	}

	public boolean haveJin() {
		return false;
	}

	public boolean isHZRoom() {
		return false;
	}

	public int getNiaoScore() {
		return 0;
	}

	public List<Card> getLuckCard() {
		return null;
	}

	public static void main(String[] args) {
		User u1 = UserUtils.getUserByImei("1");
		Player p1 = new Player(u1);
		SHRoom room = new SHRoom(u1.getPrimaryKey());
		room.setRoomSetting(new RoomSetting());
		room.addPlayer(p1);
		room.startGame();
		Card outCard = p1.getHand().cards.get(0);
		room.handOutNoLock(u1.getPrimaryKey(), outCard, false);
	}

	public void changeZhuang(String string) {
		// 代开房时更改庄家Id
		zhuangId = string;
	}

	public int calMa() {
		//
		int ma = 0;
		if (maList.size() < 1) {
			return 0;
		}
		for (int i = 0; i < maList.size(); i++) {
			Card card = maList.get(i);
			if (card.getType() <= CardType.BING) {
				if (card.getIndex() == 1 || card.getIndex() == 5 || card.getIndex() == 9) {
					ma += 1;
				}
			} else {
				if (card.getType() == 4 || card.getType() == 8) {
					ma += 1;
				}
			}
		}
		return ma;
	}
}
